-- 基于 ProximityPrompt 的自动赠礼
-- 不依赖 FireServer/InvokeServer，直接触发 Gift 提示

local Players = game:GetService("Players")
local RunService = game:GetService("RunService")

local LocalPlayer = Players.LocalPlayer

local config = {
	targetPlayer = "mayue0827",
	itemSlot = 5,          -- 快捷栏槽位（若需要先装备）
	tradeDistance = 10,
	holdDurationPadding = 0.1, -- 比提示要求多按一点时间
	autoAcceptOnReceiver = true, -- 接收端自动接受
}

local function log(msg)
	print("[ProxGift] " .. msg)

	local ok = pcall(function()
		appendfile("prox_gift_log.txt", "[ProxGift] " .. msg .. "\n")
	end)
	if not ok then
		pcall(function()
			writefile("prox_gift_log.txt", "[ProxGift] " .. msg .. "\n")
		end)
	end
end

local function getTarget()
	return Players:FindFirstChild(config.targetPlayer) or Players:GetPlayers()[2]
end

local function moveNear(target)
	if not (LocalPlayer.Character and target and target.Character) then return false end
	local myHum = LocalPlayer.Character:FindFirstChildOfClass("Humanoid")
	local root = target.Character:FindFirstChild("HumanoidRootPart")
	if not (myHum and root) then return false end
	myHum:MoveTo(root.Position)
	local tries = 0
	while tries < 40 do
		tries = tries + 1
		local meRoot = LocalPlayer.Character:FindFirstChild("HumanoidRootPart")
		if meRoot and (meRoot.Position - root.Position).Magnitude <= config.tradeDistance then
			return true
		end
		wait(0.2)
	end
	return false
end

local function equipHotbar(slot)
	-- 常见执行器提供 VirtualInput/按键；这里尝试选中工具栏槽位
	pcall(function()
		game:GetService("VirtualInputManager"):SendKeyEvent(true, Enum.KeyCode["One"].Value + (slot - 1), false, game)
		wait(0.05)
		game:GetService("VirtualInputManager"):SendKeyEvent(false, Enum.KeyCode["One"].Value + (slot - 1), false, game)
	end)
end

local function findGiftPromptAround(target)
	if not (target and target.Character) then return nil end
	local root = target.Character:FindFirstChild("HumanoidRootPart")
	if not root then return nil end

	local closest, bestDist
	for _, d in ipairs(workspace:GetDescendants()) do
		if d:IsA("ProximityPrompt") then
			local ok, part = pcall(function() return d.Parent and d.Parent:IsA("Attachment") and d.Parent.Parent or d.Parent end)
			local anchor = part and part:FindFirstChild("Position") and part or (part and part:IsA("BasePart") and part or nil)
			local pos
			if anchor and anchor:IsA("BasePart") then pos = anchor.Position end
			if pos then
				local dist = (pos - root.Position).Magnitude
				if not bestDist or dist < bestDist then
					-- 只筛 Gift 提示
					if tostring(d.ActionText):lower():match("gift") then
						closest, bestDist = d, dist
					end
				end
			end
		end
	end
	return closest
end

local function firePrompt(prompt)
	if not prompt then return false end
	log("尝试触发 Gift 提示: " .. tostring(prompt))
	-- 优先使用 fireproximityprompt（若可用）
	if typeof(fireproximityprompt) == "function" then
		pcall(function()
			fireproximityprompt(prompt, prompt.HoldDuration + config.holdDurationPadding)
		end)
		return true
	end
	-- 退化：使用 PromptButtonHoldBegan/Ended 模拟
	local ok = pcall(function()
		prompt:InputHoldBegin()
		wait((prompt.HoldDuration or 0) + config.holdDurationPadding)
		prompt:InputHoldEnd()
	end)
	return ok
end

local function execute()
	log("开始基于 ProximityPrompt 的自动赠礼…")
	local target = getTarget()
	if not target then log("找不到目标玩家") return false end

	-- 靠近
	if not moveNear(target) then log("无法靠近目标") return false end

	-- 装备物品（若游戏需要）
	if config.itemSlot then equipHotbar(config.itemSlot) end

	-- 查找并触发 Gift 提示
	local prompt = findGiftPromptAround(target)
	if not prompt then log("附近未发现 Gift 提示") return false end
	local ok = firePrompt(prompt)
	if ok then
		log("已触发 Gift 提示，等待对方 UI…")
		return true
	end
	log("触发失败")
	return false
end

-- 快捷键
game:GetService("UserInputService").InputBegan:Connect(function(input, gp)
	if gp then return end
	if input.KeyCode == Enum.KeyCode.T then
		execute()
	end
end)

log("ProximityPrompt 自动赠礼脚本已加载。按 T 开始。目标=" .. config.targetPlayer)

-- ================= 接收端自动接受（整合） =================
-- 屏蔽“Trade expired!”提示，防止刷屏
local function suppressExpiredSpam()
	local pg = LocalPlayer:FindFirstChild("PlayerGui")
	if not pg then return end
	local function hide(node)
		pcall(function()
			if node:IsA("TextLabel") and tostring(node.Text):lower():match("trade expired") then
				node.Visible = false
				node.TextTransparency = 1
				if node.Parent then node.Parent.Visible = false end
			end
		end)
	end
	for _, d in ipairs(pg:GetDescendants()) do hide(d) end
	pg.DescendantAdded:Connect(hide)
end
local function getTradingGui()
	local pg = LocalPlayer:FindFirstChild("PlayerGui")
	if not pg then return nil end
	for _, sg in ipairs(pg:GetChildren()) do
		if sg:IsA("ScreenGui") and (sg.Name:lower():match("trade") or sg.Name:lower():match("gift")) then
			return sg
		end
	end
	return nil
end

local function getUiPath(inst)
	local names = {}
	local cur = inst
	while cur and cur ~= game do
		table.insert(names, 1, cur.Name)
		cur = cur.Parent
	end
	return table.concat(names, "/")
end

local function dumpAround(node)
	if not node then return end
	local parent = node.Parent
	log("[UI] 按钮路径: " .. getUiPath(node))
	if parent then
		log("[UI] 父级: " .. getUiPath(parent))
		local siblings = {}
		for _, s in ipairs(parent:GetChildren()) do
			table.insert(siblings, s.Name .. "(" .. s.ClassName .. ")")
		end
		log("[UI] 同级: " .. table.concat(siblings, ", "))
	end
end

local function findAcceptButtonRecursive(parent)
	for _, child in ipairs(parent:GetChildren()) do
		if child:IsA("TextButton") or child:IsA("ImageButton") or child:IsA("GuiButton") then
			local name = child.Name:lower()
			local text = ""
			if child:IsA("TextButton") then
				text = (child.Text or ""):lower()
			end
			if name:match("accept") or name:match("yes") or name:match("confirm") or text:match("accept") or text:match("yes") or text:match("confirm") then
				return child
			end
		end
		-- 若是 TextLabel 写着 Accept，但父级/兄弟才是可点击按钮
		if child:IsA("TextLabel") then
			local text = (child.Text or ""):lower()
			if text:match("accept") or text:match("yes") or text:match("confirm") then
				-- 父级是否是按钮
				local p = child.Parent
				if p and (p:IsA("TextButton") or p:IsA("ImageButton") or p:IsA("GuiButton")) then
					return p
				end
				-- 查找同级按钮
				for _, sib in ipairs(child.Parent and child.Parent:GetChildren() or {}) do
					if sib:IsA("TextButton") or sib:IsA("ImageButton") or sib:IsA("GuiButton") then
						return sib
					end
				end
				-- 退化：直接点这个 TextLabel
				return child
			end
		end
		local found = findAcceptButtonRecursive(child)
		if found then return found end
	end
	return nil
end

local function tryClickButton(btn)
	local ok
	-- 直接触发绑定的回调（需要支持 getconnections）
	local function fireConnections(sig)
		if typeof(getconnections) == "function" and sig then
			pcall(function()
				for _, conn in ipairs(getconnections(sig)) do
					local fn = conn.Function or conn.function or conn.Callback
					if typeof(fn) == "function" then
						pcall(fn)
					end
					if conn.Fire then pcall(function() conn:Fire() end) end
				end
			end)
		end
	end
	fireConnections(btn.MouseButton1Click)
	fireConnections(btn.Activated)
	fireConnections(btn.MouseButton1Down)
	fireConnections(btn.MouseButton1Up)
	-- 直接 firesignal 系列
	if typeof(firesignal) == "function" then
		pcall(function()
			if btn.MouseEnter then firesignal(btn.MouseEnter) end
			if btn.MouseButton1Down then firesignal(btn.MouseButton1Down) end
			if btn.MouseButton1Click then firesignal(btn.MouseButton1Click) end
			if btn.MouseButton1Up then firesignal(btn.MouseButton1Up) end
			if btn.Activated then firesignal(btn.Activated) end
		end)
		-- 给一点时间
		wait(0.02)
		-- 若 firesignal 可用，认为已尝试
	end
	ok = pcall(function() btn:Fire("MouseButton1Click") end)
	if ok then return true end
	ok = pcall(function() btn:Fire("Activated") end)
	if ok then return true end
	ok = pcall(function() if btn.Activate then btn:Activate() end end)
	if ok then return true end
	if btn:IsA("TextButton") and btn.Activated then
		ok = pcall(function() btn.Activated:Fire() end)
		if ok then return true end
	end
	-- 组合模拟
	ok = pcall(function()
		btn:Fire("MouseEnter")
		wait(0.05)
		btn:Fire("MouseButton1Down")
		wait(0.05)
		btn:Fire("MouseButton1Up")
		btn:Fire("MouseLeave")
	end)
	return ok
end

local function virtualClickGuiCenter(gui)
	local vim = game:GetService("VirtualInputManager")
	if not (gui and gui.AbsolutePosition) then return false end
	local pos = gui.AbsolutePosition
	local size = gui.AbsoluteSize
	local x = pos.X + size.X/2
	local y = pos.Y + size.Y/2
	local ok = pcall(function()
		vim:SendMouseMoveEvent(x, y, game)
		vim:SendMouseButtonEvent(x, y, 0, true, game, 0)
		wait(0.05)
		vim:SendMouseButtonEvent(x, y, 0, false, game, 0)
	end)
	return ok
end

-- 更强力：多次定位并点击，直到命中该 GUI（通过 GetGuiObjectsAtPosition 判断）
local function forceClickGui(gui)
	local vim = game:GetService("VirtualInputManager")
	local uis = game:GetService("UserInputService")
	if not (gui and gui.AbsolutePosition) then return false end
	local center = gui.AbsolutePosition + gui.AbsoluteSize/2
	local tries = 0
	local success = false
	while tries < 12 do
		tries = tries + 1
		pcall(function()
			vim:SendMouseMoveEvent(center.X, center.Y, game)
			vim:SendMouseButtonEvent(center.X, center.Y, 0, true, game, 0)
			wait(0.02)
			vim:SendMouseButtonEvent(center.X, center.Y, 0, false, game, 0)
		end)
		-- 命中检测
		local objs = uis:GetGuiObjectsAtPosition(center.X, center.Y)
		for _, o in ipairs(objs) do
			if o == gui then success = true break end
		end
		if success then break end
		wait(0.03)
	end
	return success
end

-- 触摸点击（部分界面只响应触摸）
local function touchTapGui(gui)
    local vim = game:GetService("VirtualInputManager")
    if not (gui and gui.AbsolutePosition) then return false end
    local center = gui.AbsolutePosition + gui.AbsoluteSize/2
    local ok = pcall(function()
        -- touchId=1, down=true/false
        vim:SendTouchEvent(center.X, center.Y, 1, true)
        wait(0.03)
        vim:SendTouchEvent(center.X, center.Y, 1, false)
    end)
    return ok
end

local function autoAcceptLoop()
	if not config.autoAcceptOnReceiver then return end
	local pg = LocalPlayer:WaitForChild("PlayerGui")

	local lastAcceptAt = 0

    -- 针对已知路径的定向点击（优先）
    local function clickKnownGiftPath()
        local ui = pg:FindFirstChild("Gift_Notification")
        if not ui then return false end
        local frame1 = ui:FindFirstChild("Frame")
        if not frame1 then return false end
        local frame2 = frame1:FindFirstChild("Gift_Notification")
        if not frame2 then return false end
        local holder = frame2:FindFirstChild("Holder")
        if not holder then return false end
        local frame = holder:FindFirstChild("Frame")
        if not frame then return false end
        local accept = frame:FindFirstChild("Accept")
        if not accept then return false end

        log("命中已知路径，直接点击: " .. getUiPath(accept))
        if tryClickButton(accept) or virtualClickGuiCenter(accept) or forceClickGui(accept) or touchTapGui(accept) then
            return true
        end
        -- 强制关闭 UI（有些服 Accept 只是客户端关闭提示）
        pcall(function()
            frame.Visible = false
            holder.Visible = false
            frame2.Visible = false
            ui.Enabled = false
        end)
        return false
    end

    local function tryServerAccept()
        local okAny = false
        local function try(fn)
            local ok = pcall(fn)
            okAny = okAny or ok
        end
        local ReplicatedStorage = game:GetService("ReplicatedStorage")
        local ge = ReplicatedStorage:FindFirstChild("GameEvents")
        if ge then
			log("autoAcceptLoop服务器接受事件")
            -- 方式1：AcceptPetGift（根目录）
            try(function()
                local ev = ge:FindFirstChild("AcceptPetGift")
                if ev then ev:FireServer() end
            end)
            -- 方式2：Gift 文件夹下的 AcceptPetGift
            try(function()
                local gift = ge:FindFirstChild("Gift")
                if gift then
                    local ev = gift:FindFirstChild("AcceptPetGift")
                    if ev then ev:FireServer() end
                end
            end)
            -- 方式3：TradeEvents.Accept
            try(function()
                local trade = ge:FindFirstChild("TradeEvents")
                if trade then
                    local ev = trade:FindFirstChild("Accept")
                    if ev then ev:FireServer() end
                end
            end)
        end
        if okAny then
            log("已通过服务器事件尝试接受礼物/交易")
        else
            log("未找到可用的服务器接受事件")
        end
    end
    local function isGiftUiVisible()
        local pg = LocalPlayer:FindFirstChild("PlayerGui")
        if not pg then return false end
        local ui = pg:FindFirstChild("Gift_Notification")
        if not ui or not ui.Enabled then return false end
        return true
    end

    local function robustAccept()
        -- 冷却，避免重复提交导致过期
        if tick() - lastAcceptAt < 3 then return end
        lastAcceptAt = tick()

        -- 简化为一次性接受：等待 UI 稳定后只触发一次服务器事件
        wait(0.15)
        tryServerAccept()

        -- 同时尝试一次已知路径点击（部分服为纯前端按钮）
        pcall(function()
            if clickKnownGiftPath() then
                log("已通过已知路径完成接受")
            else
                local gui = getTradingGui()
                if gui then
                    local btn = findAcceptButtonRecursive(gui)
                    if btn then
                        -- 三连点击：事件 + 虚拟鼠标 + 强力定位
                        tryClickButton(btn)
                        virtualClickGuiCenter(btn)
                        forceClickGui(btn)
                        touchTapGui(btn)
                    end
                end
            end
        end)

        -- 最多观察 1.5 秒，期间不再重复触发
        local t0 = tick()
        while tick() - t0 < 1.5 do
            if not isGiftUiVisible() then
                log("确认 Gift UI 已关闭")
                return
            end
            wait(0.1)
        end
    end

    local function handle()
        if not isGiftUiVisible() then return end
        robustAccept()
    end

	-- 监听 UI 出现
    pg.ChildAdded:Connect(function()
		-- 稍等确保元素就绪
		wait(0.1)
		handle()
	end)
	pg.DescendantAdded:Connect(function(inst)
		if inst:IsA("TextButton") or inst:IsA("ImageButton") or inst:IsA("GuiButton") then
			if inst.Name:lower():match("accept") then
				wait(0.05)
				tryClickButton(inst)
				log("在 DescendantAdded 中尝试点击: " .. inst.Name)
			end
		end
	end)

	-- 周期轮询兜底
	spawn(function()
		while true do
			handle()
			wait(0.5)
		end
	end)
end

autoAcceptLoop()

-- 启动刷屏抑制
suppressExpiredSpam()


